package edu.tfh.s2.ehkbot.gerete;

import edu.tfh.s2.ehkbot.daten.AdressenDispatcher;
import edu.tfh.s2.ehkbot.daten.Einstellungen;
import edu.tfh.s2.ehkbot.daten.InitFactory;
import edu.tfh.s2.ehkbot.gerete.aktoren.BiStateAktor;
import edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor;
import edu.tfh.s2.ehkbot.gerete.sensoren.BarcodeScanner;
import edu.tfh.s2.ehkbot.gerete.sensoren.Bild;
import edu.tfh.s2.ehkbot.gerete.sensoren.Kamera;
import edu.tfh.s2.ehkbot.gerete.sensoren.Sensor;
import edu.tfh.s2.ehkbot.util.Subject;

/**
 * Der Greifer mit Saugnäpfen und E-Magenten.
 * 
 * @author s2zehn
 */
public class Greifer extends Subject {

	public static final String modulName = "Greifer";
	private Sensor abstandsSensor;
	private BarcodeScanner barcodeScanner;
	private BiStateAktor eMagene;
	private MotorAktor greiferMotor;
	private Kamera kamera;
	private Sensor kraft;
	private BiStateAktor saugnapf;
	private Sensor saugnapfDruckSensor;

	/**
	 * Konstruktor für Greifer.
	 */
	public Greifer() {
		InitFactory intf = InitFactory.getInstance();
		AdressenDispatcher adrD = AdressenDispatcher.getInstance();
		kamera = intf.getKamera();
		kraft = intf.getSensor(adrD.getAdresseFor(modulName, "kraft"));
		greiferMotor = intf.getMotorAktor(adrD.getAdresseFor(modulName, "greiferMotor"));
		barcodeScanner = intf.getBarcodeScanner();
		saugnapfDruckSensor = intf.getSensor(adrD.getAdresseFor(modulName, "saugnapfDruck"));
		saugnapf = intf.getBiStateAktor(adrD.getAdresseFor(modulName, "saugnapf"));
		eMagene = intf.getBiStateAktor(adrD.getAdresseFor(modulName, "eMagene"));
		abstandsSensor = intf.getSensor(adrD.getAdresseFor(modulName, "abstands"));
	}

	/**
	 * Testet ob eindie Kraft-, Abstands- und Drucksensoren drauf schlißen lassen das etwas gegriffen wurde.
	 * 
	 * @return True wenn der Greifer etwas gegriffen hat.
	 */
	public boolean gegriffen() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		double istAngesaugtDruckGrenze = Einstellungen.getInstance().getDoublePropertie(
			"IstAngesaugtDruckGrenzeBar");
		double istNahDran = Einstellungen.getInstance().getDoublePropertie("IstNahDranGrenzeMm");
		double istGegrifenKraftGrenzeN = Einstellungen.getInstance().getDoublePropertie(
			"IstGegrifenKraftGrenzeN");
		return abstandsSensor.getMesswert() < istNahDran
						&& saugnapfDruckSensor.getMesswert() < istAngesaugtDruckGrenze
						&& kraft.getMesswert() > istGegrifenKraftGrenzeN;
	}

	/**
	 * Liefert das Bild welches die Kamer sieht.
	 * 
	 * @return Das Bild.
	 */
	public Bild getBild() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		return kamera.getBild();
	}

	/**
	 * Liefert die Kamera.
	 * 
	 * @return Die Kamera
	 */
	public Kamera getKamera() {
		return kamera;
	}

	/**
	 * Aktiviert die Aktoren um zu greifen.
	 */
	public void greifen() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		double istGegrifenKraftGrenzeN = Einstellungen.getInstance().getDoublePropertie(
			"IstGegrifenKraftGrenzeN");
		saugnaepfeAktivieren();
		magneteAktivieren();
		double greiferGeschlossen = Einstellungen.getInstance().getDoublePropertie("GreiferGeschlossen");

		int schite = 100;
		for (int i = 0; i < schite; ++i) {
			greiferMotor.drehe(greiferGeschlossen / schite);
			greiferMotor.waitUntilDone();
			if (kraft.getMesswert() < istGegrifenKraftGrenzeN) {
				greiferMotor.stope();
				break;
			}
		}
	}

	/**
	 * Aktiviert die Aktoren um greifen aufzuheben.
	 */
	public void greifenAufheben() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		saugnaepfeDeaktivieren();
		magneteDeaktivieren();
		double GreiferGeoeffnet = Einstellungen.getInstance().getDoublePropertie("GreiferGeoeffnet");
		double greiferMotorGrad = greiferMotor.getDrehung();
		double zuDrehen = greiferMotorGrad - GreiferGeoeffnet;
		greiferMotor.drehe(zuDrehen);

	}

	/**
	 * Prüft ob greifen möglich ist.
	 * 
	 * @return true wenn greifen möglich ist.
	 */
	public boolean greifenMoeglich() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		double istNahDran = Einstellungen.getInstance().getDoublePropertie("IstNahDranGrenzeMm");
		return abstandsSensor.getMesswert() < istNahDran;
	}

	/**
	 * Aktiviert die E-Magneten.
	 * 
	 * @return true fals E-Magnete aktiviert wurden.
	 */
	public boolean magneteAktivieren() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		eMagene.aktiviere();
		return eMagene.istAktiviert();
	}

	/**
	 * Deaktiviert die E-Magnete.
	 * 
	 * @return true fals sie Deaktiviert wurden.
	 */
	private boolean magneteDeaktivieren() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		eMagene.deaktiviere();
		return !eMagene.istAktiviert();
	}

	/**
	 * Aktivert die Saugnäpfe.
	 * 
	 * @return true fals die Saugnäpfe Aktivert worden sind und der Druck dadurch gesunken ist.
	 */
	public boolean saugnaepfeAktivieren() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		double istAngesaugtDruckGrenze = Einstellungen.getInstance().getDoublePropertie(
			"IstAngesaugtDruckGrenzeBar");
		saugnapf.aktiviere();
		return saugnapf.istAktiviert() && saugnapfDruckSensor.getMesswert() < istAngesaugtDruckGrenze;
	}

	/**
	 * Deaktiviert die Saugnäpfe.
	 * 
	 * @return true fals die Saugnäpfe deaktiviert worden sind.
	 */
	private boolean saugnaepfeDeaktivieren() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		saugnapf.deaktiviere();
		return !saugnapf.istAktiviert();
	}

	/**
	 * Läst den Barcodescanner Scannen.
	 * 
	 * @return Den Barcode.
	 */
	public int scanBarcode() {
		setState(Thread.currentThread().getStackTrace()[1].getMethodName());
		return barcodeScanner.scanneBarcode();
	}
}